/*!
  @file   VectorTypes.hpp
  @author Jared Marsau
  @author Hamza Hutchinson
  @date   03/01/2009
  @brief  
    This header file outlines the interface for 2, 3, and 4 dimensional vectors.
*/

#ifndef VECTOR_TYPES_HPP
#define VECTOR_TYPES_HPP

#include "MathUtility.hpp"

namespace VectorTypes
{
  /*!
  @brief
    This defines a 2 dimensional vector, its operators, and methods.
  */
  struct Vector2D
  {
    //Constructors
    Vector2D();
    Vector2D(const float* arrayOfTwoFloats);
    Vector2D(float xVal, float yVal);

    //Assignment operators
    Vector2D& operator =  (const Vector2D& rhs);
    Vector2D& operator += (const Vector2D& rhs);
    Vector2D& operator -= (const Vector2D& rhs);
    Vector2D& operator *= (float rhs);
    Vector2D& operator /= (float rhs);

    //Unary operators
    Vector2D     operator -  () const;
    float&       operator [] (unsigned index);
    const float& operator [] (unsigned index) const;

    //Binary operators
    Vector2D operator + (const Vector2D& rhs) const;
    Vector2D operator - (const Vector2D& rhs) const;
    float    operator * (const Vector2D& rhs) const;
    Vector2D operator * (float rhs)           const;
    Vector2D operator / (float rhs)           const;

    bool operator == (const Vector2D& rhs) const;
    bool operator != (const Vector2D& rhs) const;

    //Methods
    void         Set           (float xVal, float yVal);
    void         Set           (const Vector2D& source);
    float*       GetArrayPtr   ();
    const float* GetArrayPtr   () const;
    void         Normalize     ();

    float        Length        ()                                            const;
    float        LengthSquared ()                                            const;
    Vector2D     Normalized    ()                                            const;
    bool         IsZeroLength  (float tolerance = MathUtility::MATH_EPSILON) const;

    //Members
    float x, y;
  };
  
  Vector2D operator * (float lhs, const Vector2D& rhs);
  
  /*!
  @brief
    This defines a 3 dimensional vector, its operators, and methods.
  */
  struct Vector3D
  {
    //Constructors
    Vector3D();
    Vector3D(const float* arrayOfThreeFloats);
    Vector3D(float xVal, float yVal, float zVal);
    
    //Assignment operators
    Vector3D& operator =  (const Vector3D& rhs);
    Vector3D& operator += (const Vector3D& rhs);
    Vector3D& operator -= (const Vector3D& rhs);
    Vector3D& operator *= (float rhs);
    Vector3D& operator /= (float rhs);
    
    //Unary operators
    Vector3D     operator -  () const;
    float&       operator [] (unsigned index);
    const float& operator [] (unsigned index) const;
    
    //Binary operators
    Vector3D operator + (const Vector3D& rhs) const;
    Vector3D operator - (const Vector3D& rhs) const;
    float    operator * (const Vector3D& rhs) const;
    Vector3D operator ^ (const Vector3D& rhs) const;
    Vector3D operator * (float rhs)           const;
    Vector3D operator / (float rhs)           const;
    
    bool operator == (const Vector3D& rhs) const;
    bool operator != (const Vector3D& rhs) const;
    
    //Methods
    void         Set           (float xVal, float yVal, float zVal);
    void         Set           (const Vector3D& source);
    float*       GetArrayPtr   ();
    const float* GetArrayPtr   () const;
    void         Normalize     ();
    float        Length        ()                                       const;
    float        LengthSquared ()                                       const;
    Vector3D     Normalized    ()                                       const;
    bool         IsZeroLength  (float tolerance = MathUtility::MATH_EPSILON) const;
    
    //Members
    float x, y, z;
  };
  
  Vector3D operator * (float lhs, const Vector3D& rhs);
  
  /*!
  @brief
    This defines a 4 dimensional vector, its operators, and methods.
  */
  struct Vector4D
  {
    //Constructors
    Vector4D();
    Vector4D(const float* arrayOfFourFloats);
    Vector4D(const Vector3D& xyzVal, float wVal);
    Vector4D(float xVal, float yVal, float zVal, float wVal);
    
    //Assignment operators
    Vector4D& operator =  (const Vector4D& rhs);
    Vector4D& operator += (const Vector4D& rhs);
    Vector4D& operator -= (const Vector4D& rhs);
    Vector4D& operator *= (float rhs);
    Vector4D& operator /= (float rhs);
    
    //Unary operators
    Vector4D     operator -  () const;
    float&       operator [] (unsigned index);
    const float& operator [] (unsigned index) const;
    
    //Binary operators
    Vector4D operator + (const Vector4D& rhs) const;
    Vector4D operator - (const Vector4D& rhs) const;
    float    operator * (const Vector4D& rhs) const;
    Vector4D operator * (float rhs)           const;
    Vector4D operator / (float rhs)           const;
    
    bool operator == (const Vector4D& rhs) const;
    bool operator != (const Vector4D& rhs) const;
    
    //Methods
    void         HomogeneousDivide();
    void         Set              (float xVal, float yVal, float zVal, float wVal);
    void         Set              (const Vector4D& source);
    void         Set              (const Vector3D& xyzVal, float wVal);
    float*       GetArrayPtr      ();
    const float* GetArrayPtr      () const;
    void         Normalize        ();
    float        Length           ()                                       const;
    float        LengthSquared    ()                                       const;
    Vector4D     Normalized       ()                                       const;
    bool         IsZeroLength     (float tolerance = MathUtility::MATH_EPSILON) const;
    
    //Members
    float x, y, z, w;
  };
  
  Vector4D operator * (float lhs, const Vector4D& rhs);
  
}//namespace VectorTypes

#endif
